/**********************************************************************************************************************
 *
 * Project:    mGameEngine
 * File:       aseloader.cpp
 * Author:     sergio
 * Created on: 2009-05-08
 *
 **********************************************************************************************************************/

#include "aseloader.h"

namespace mGameEngine
{
namespace Graphics
{

const int AseLoader::BUF_SIZE = 100;

AseLoader::AseLoader() :
    MeshLoader()
{
}

AseLoader::AseLoader(const String &filename) :
    MeshLoader(filename),
    _vertices(0)
{
}

AseLoader::~AseLoader()
{
    if(_vertices)
    {
        delete _vertices;
    }
}

void AseLoader::load()
{
    _state = 0.0f;
    char buf[BUF_SIZE];
    FILE* f;

    f = fopen(_filename,"rb");
    if (f==NULL)
        return;

    fseek(f,0,SEEK_END);
    int filesize = ftell(f);
    fseek(f,0,SEEK_SET);
    char *filebuf = new char[filesize+1];
    filebuf[filesize] = 0;
    fread(filebuf,filesize,1,f);
    fclose(f);

    int ptr = 0;
    for (int i=0;;++i)
    {
        char* r;
        r=readNode(filebuf,&ptr,buf,BUF_SIZE);
        if (r==0)
            break;
        else
        {
            if (std::strcmp(buf,"*MATERIAL_LIST")==0)
            {
                //readMaterialList(r);
            } else
            if (std::strcmp(buf,"*GEOMOBJECT")==0)
                readGeomObj(r);

            delete[] r;
        }
    }

    Vector<Face>::iterator fIt = _faces->begin();
    Vector<Face>::iterator tfIt = _tFaces->begin();
    Vector<Group> groups;
    Group g;
    g.material = 0;//new Material();

    while (fIt!=_faces->end() && tfIt!=_tFaces->end())
    {
        (*_vertices)[fIt->vertices[0]].texCoords[0].x = (*_tVertices)[tfIt->vertices[0]].x;
        (*_vertices)[fIt->vertices[0]].texCoords[0].y = (*_tVertices)[tfIt->vertices[0]].y;
        (*_vertices)[fIt->vertices[1]].texCoords[0].x = (*_tVertices)[tfIt->vertices[1]].x;
        (*_vertices)[fIt->vertices[1]].texCoords[0].y = (*_tVertices)[tfIt->vertices[1]].y;
        (*_vertices)[fIt->vertices[2]].texCoords[0].x = (*_tVertices)[tfIt->vertices[2]].x;
        (*_vertices)[fIt->vertices[2]].texCoords[0].y = (*_tVertices)[tfIt->vertices[2]].y;
        g.faces.push_back(*fIt);
        ++fIt;
        ++tfIt;
    }
    groups.push_back(g);
    _mesh = new Mesh(*_vertices, groups, Vector<Bone>());
    _state = 1.0f;//0.5f;



    return;
/*    Vector<Group> groups;
    Vector<int> ids;    // zbior ID'�w materia�u

    fIt = _faces->begin();
    Vector<int>::iterator idIt = _mtlID->begin();

    while (fIt!=_faces->end() && idIt!=_mtlID->end())
    {
        Vector<int>::iterator idsIt = ids.begin();
        Vector<Group>::iterator groupsIt = groups.begin();
        while (*idsIt!=*idIt)
        {
            if (idsIt==ids.end())
            {
                ids.push_back(*idIt);
                idsIt = --ids.end();
                Group g;
                groups.push_back(g);
                groupsIt = --groups.end();
            }
            ++idsIt;
            ++groupsIt;
        }
        groupsIt->faces.push_back(*fIt);
        ++fIt;
        ++idIt;
    }*/
    _state = 1.0f;
}

bool AseLoader::readString(const char* src,int* ptr,char* str,int len)
{
    char c;
    int i=0;
    int pos=*ptr;

    for (;;)
    {
        if ((c=src[(*ptr)++])==0)
        {
            *ptr=pos;
            return false;
        }
        if (!isspace(c))
            break;
    }

    for (;;)
    {
        str[i++]=c;

        if (i==len || (c=src[(*ptr)++])==0)
        {
            *ptr=pos;
            return false;
        }

        if (isspace(c))
            break;
    }

    str[i]=0;

    return true;
}

int AseLoader::readLine(const char* node, int* ptr, char* buf)
{
    if (buf==0)
    {
        int pos=*ptr,i=0;
        char c;
        for (;;)
        {
            c=node[(*ptr)++];
            if (c==0x0A || c==0x0D)
                break;
            ++i;
        }
        *ptr=pos;
        return i;
    } else
    {
        int i=0;
        for (;;)
        {
            buf[i]=node[(*ptr)++];
            if (buf[i]==0x0A || buf[i]==0x0D)
                break;
            ++i;
        }
        ++(*ptr);
        buf[i]=0;
        return i;
    }
}

char* AseLoader::readNode(const char* node, int* ptr, char* nodename, int len)
{
    if (!readString(node,ptr,nodename,len))
    {
        nodename[0]=0;
        return 0;
    }

    char c;
    int pos=*ptr;
    for (;;)
    {
        c=node[(*ptr)++];
        if (c==0x0A || c==0x0D || c=='{')
            break;
    }

    if (c=='{')
    {
        int pos=*ptr,size=0;
        for (int i=1;i>0;)
        {
            c=node[(*ptr)++];
            ++size;
            if (c=='{')
                ++i;
            if (c=='}')
                --i;
        }
        *ptr=pos;
        char* buf=new char[size+1];
        for (int i=0;i<size;++i)
            buf[i]=node[(*ptr)++];
        buf[size]=0;
        return buf;
    } else
    {
        *ptr=pos-1;
        char* buf=new char[readLine(node,ptr,0)+1];
        readLine(node,ptr,buf);
        return buf;
    }
}
/*
void AseLoader::readMapDiffuse(char*node, int matNum)
{
    int ptr=0;
    char buf[BUF_SIZE];
    for (;;)
    {
        char* s;
        s=readNode(node,&ptr,buf,BUF_SIZE);
        if (s==0)
            break;
        else
        {
            if (strcmp(buf,"*BITMAP")==0)
            {
                materials[matNum].BITMAP=new char[strlen(s)-2];
                for (size_t i=2;i<strlen(s)-1;++i)
                    materials[matNum].BITMAP[i-2]=s[i];
                materials[matNum].BITMAP[strlen(s)-3]=0;
            }
            delete[] s;
        }
    }
}

void AseLoader::readMaterial(char* node, int matNum)
{
    int ptr=0;
    char buf[BUF_SIZE];
    for (;;)
    {
        char* s;
        s=readNode(node,&ptr,buf,BUF_SIZE);
        if (s==0)
            break;
        else
        {
//            printf("\t%s %d\n",buf,strlen(s));
            if (strcmp(buf,"*MATERIAL_NAME")==0)
            {
                materials[matNum].MATERIAL_NAME=new char[strlen(s)-2];
                for (size_t i=2;i<strlen(s)-1;++i)
                    materials[matNum].MATERIAL_NAME[i-2]=s[i];
                materials[matNum].MATERIAL_NAME[strlen(s)-3]=0;
                //printf("\tmatName: \\%s\\\n",materials[matNum].MATERIAL_NAME);
            } else
            if (strcmp(buf,"*MATERIAL_AMBIENT")==0)
            {
                sscanf_s(s,"%lf%lf%lf",    &materials[matNum].MATERIAL_AMBIENT_R,
                                        &materials[matNum].MATERIAL_AMBIENT_G,
                                        &materials[matNum].MATERIAL_AMBIENT_B);
            } else
            if (strcmp(buf,"*MATERIAL_DIFFUSE")==0)
            {
                sscanf_s(s,"%lf%lf%lf",    &materials[matNum].MATERIAL_DIFFUSE_R,
                                        &materials[matNum].MATERIAL_DIFFUSE_G,
                                        &materials[matNum].MATERIAL_DIFFUSE_B);
            } else
            if (strcmp(buf,"*MATERIAL_SPECULAR")==0)
            {
                sscanf_s(s,"%lf%lf%lf",    &materials[matNum].MATERIAL_SPECULAR_R,
                                        &materials[matNum].MATERIAL_SPECULAR_G,
                                        &materials[matNum].MATERIAL_SPECULAR_B);
            } else
            if (strcmp(buf,"*MATERIAL_SHINE")==0)
            {
                sscanf_s(s,"%lf",    &materials[matNum].MATERIAL_SHINE);
            } else
            if (strcmp(buf,"*MATERIAL_SHINESTRENGTH")==0)
            {
                sscanf_s(s,"%lf",    &materials[matNum].MATERIAL_SHINESTRENGTH);
            } else
            if (strcmp(buf,"*MATERIAL_TRANSPARENCY")==0)
            {
                sscanf_s(s,"%lf",    &materials[matNum].MATERIAL_TRANSPARENCY);
            } else
            if (strcmp(buf,"*MAP_DIFFUSE")==0)
            {
                readMapDiffuse(s,matNum);
            }
            delete[] s;
        }
    }
}

void AseLoader::readMaterialList(char* node)
{
    int ptr=0;
    char buf[BUF_SIZE];
    int mat=0;
    for (;;)
    {
        char* s;
        s=readNode(node,&ptr,buf,BUF_SIZE);
        if (s==0)
            break;
        else
        {
//            printf("\t%s %d\n",buf,strlen(s));
            if (strcmp(buf,"*MATERIAL_COUNT")==0)
            {
                sscanf_s(s,"%d",&materialsCount);
                if (materialsCount>0)
                    materials=new Material[materialsCount];
                //printf("\tmatCount: %d\n",materialsCount);
            } else
            if (strcmp(buf,"*MATERIAL")==0)
            {
                readMaterial(s,mat++);
            }
            delete[] s;
        }
    }
}
*/
void AseLoader::readMesh(char* node)
{
    int ptr=0;
    int actFace;
    char buf[BUF_SIZE];
    for (;;)
    {
        char* s;
        s=readNode(node,&ptr,buf,BUF_SIZE);
        if (s==0)
            break;
        else
        {
            if (std::strcmp(buf,"*MESH_NUMVERTEX")==0)
            {
                sscanf(s,"%d", &_vertexCount);
                if (_vertexCount>0)
                    _vertices = new Vector<Vertex>(_vertexCount);
            } else
            if (strcmp(buf,"*MESH_NUMFACES")==0)
            {
                sscanf(s,"%d",    &_faceCount);
                if (_faceCount>0)
                {
                    _faces = new Vector<Face>(_faceCount);
                    _mtlID = new Vector<int>(_faceCount);
                }
            } else
            if (strcmp(buf,"*MESH_VERTEX_LIST")==0)
            {
                readMesh(s);
            } else
            if (strcmp(buf,"*MESH_FACE_LIST")==0)
            {
                readMesh(s);
            } else
            if (strcmp(buf,"*MESH_NUMTVERTEX")==0)
            {
                sscanf(s,"%d",    &_tVertexCount);
                if (_tVertexCount>0)
                    _tVertices = new Vector<Vector3>(_tVertexCount);
            } else
            if (strcmp(buf,"*MESH_TVERTLIST")==0)
            {
                readMesh(s);
            } else
            if (strcmp(buf,"*MESH_NUMTVFACES")==0)
            {
                sscanf(s,"%d", &_tFaceCount);
                if (_tFaceCount>0)
                    _tFaces = new Vector<Face>(_tFaceCount);
                //assert(_tFaceCount == _faceCount);    // nie wiem czy ten warunek jest konieczny...
            } else
            if (strcmp(buf,"*MESH_TFACELIST")==0)
            {
                readMesh(s);
            } else
            if (strcmp(buf,"*MESH_NORMALS")==0)
            {
                readMesh(s);
            } else
            if (strcmp(buf,"*MESH_VERTEX")==0)
            {
                int i;
                float x,y,z;
//                sscanf(s,"%d",&i);
                sscanf(s,"%d %f%f%f", &i, &x, &y, &z);
                (*_vertices)[i].position.x = x;
                (*_vertices)[i].position.y = y;
                (*_vertices)[i].position.z = z;
            } else
            if (strcmp(buf,"*MESH_FACE")==0)
            {
                int i,a,b,c;
                sscanf(s,"%d",&i);

                sscanf(std::strstr(s,"A:")+2, "%d", &a);
                sscanf(std::strstr(s,"B:")+2, "%d", &b);
                sscanf(std::strstr(s,"C:")+2, "%d", &c);

                (*_faces)[i].vertices[0] = a;
                (*_faces)[i].vertices[1] = b;
                (*_faces)[i].vertices[2] = c;
//                sscanf(strstr(s,"AB:")+3, "%d", &vab);
//                sscanf(strstr(s,"BC:")+3, "%d", &vbc);
//                sscanf(strstr(s,"CA:")+3, "%d", &vca);
                char *sub = strstr(s,"*MESH_MTLID");
                if (sub!=0)
                    sscanf(sub+11, "%d", &(*_mtlID)[i]);

            } else
            if (strcmp(buf,"*MESH_TVERT")==0)
            {
                int i;
                sscanf(s,"%d",&i);
                sscanf(s,"%*d %f%f%f",    &(*_tVertices)[i].x,
                                        &(*_tVertices)[i].y,
                                        &(*_tVertices)[i].z);
            } else
            if (strcmp(buf,"*MESH_TFACE")==0)
            {
                int i,a,b,c;
                sscanf(s,"%d",&i);
                sscanf(s,"%*d %d %d %d", &a, &b, &c);
                (*_tFaces)[i].vertices[0] = a;
                (*_tFaces)[i].vertices[1] = b;
                (*_tFaces)[i].vertices[2] = c;
            } else
            if (strcmp(buf,"*MESH_FACENORMAL")==0)
            {
                sscanf(s,"%d",&actFace);
            } else
            if (strcmp(buf,"*MESH_VERTEXNORMAL")==0)
            {
                int i;
                sscanf(s,"%d",&i);
                sscanf(s,"%*d %f%f%f",    &(*_vertices)[i].normal.x,
                                        &(*_vertices)[i].normal.y,
                                        &(*_vertices)[i].normal.z);
            } else
            if (strcmp(buf,"*TM_POS")==0)
            {
//                    sscanf_s(s,"%lf %lf %lf",    &objects[objectsCount].pos.x,
//                                                &objects[objectsCount].pos.y,
//                                                &objects[objectsCount].pos.z);
            }

            //printf("\t%s %d\n",buf,strlen(s));
            delete[] s;
        }
    }
}

void AseLoader::readGeomObj(char* node)
{
    int ptr=0;
    char buf[BUF_SIZE];
    for (;;)
    {
        char* s;
        s=readNode(node,&ptr,buf,BUF_SIZE);
        if (s==0)
            break;
        else
        {
            if (std::strcmp(buf,"*NODE_NAME")==0)
            {
//                objects[objectsCount].NODE_NAME=new char[strlen(s)-2];
//                for (size_t i=2;i<strlen(s)-1;++i)
//                    objects[objectsCount].NODE_NAME[i-2]=s[i];
//                objects[objectsCount].NODE_NAME[strlen(s)-3]=0;
            } else
            if (strcmp(buf,"*NODE_TM")==0)
            {
                readMesh(s);
            } else
            if (strcmp(buf,"*MESH")==0)
            {
                readMesh(s);
            } else
            if (strcmp(buf,"*MATERIAL_REF")==0)
            {
//                sscanf_s(s,"%d",    &objects[objectsCount].MATERIAL_REF);
            }
//            printf("\t%s %d\n",buf,strlen(s));
            delete[] s;
        }
    }

}

}

}
